/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			uvarary.cc
  \date			Dec 2011
  \author		TNick

  \brief		Contains the implementation for UVarAry class


*//*


 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Please read COPYING and README files in root folder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include	<QtGlobal>


#include	<pgscript.h>
#include	<pgscript_internal.h>

#include	<pgsave/ipgsave.h>

#include	"uvarary.h"

/*  INCLUDES    ============================================================ */
//
//
//
//
/*  DEFINITIONS    --------------------------------------------------------- */

using namespace PgScr;
using namespace PgSave;

/*  DEFINITIONS    ========================================================= */
//
//
//
//
/*  DATA    ---------------------------------------------------------------- */

/*  DATA    ================================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
UVarAry::UVarAry		( void )
	: DefVar()
{
	/* stub */
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
UVarAry::~UVarAry		( void )
{
	/* stub */
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString				UVarAry::presentation	( VarStore * uv )
{


	/* we should have been provided with an variable */
	Q_ASSERT ( uv != NULL );

	/* and that the type should have been array */
	Q_ASSERT( uv->basicType() == VTY_FLAG_ARRAY );

	/* skip empty arrays */
	if ( uv->ary.cnt == 0 )
		return "(empty)";

	/* lenght > 0 => a valid pointer is expected */
	Q_ASSERT( uv->ary.p_ary != NULL );

	/* array of VarStore elements in the array */
	VarStore * p_elem = uv->ary.p_ary;

	/* the return is a comma separate list enclosed in right brackets */
	QString s_ret( "[" );
	bool	b_first = true;

	/* get the type of the elements */
	StoreType el_ty = uv->compositeType();
	Q_ASSERT( ( el_ty >= 0 ) && ( el_ty < VTY_BASE_MAX) );

	DefVar * el_interf;

	/* if the type is a basic type then the interface needs to only be
   retieved once */
	if ( el_ty == VTY_DEFVAR )
	{
		for ( quint32 i = 0; i < uv->ary.cnt; i++ )
		{
			if ( !b_first )
				s_ret += ", ";

			b_first = false;
			el_interf = p_elem[i].dfv;
			s_ret += el_interf->presentation();
		}
	}
	else
	{
		Q_ASSERT( bldin_intf != NULL );
		el_interf = bldin_intf[ el_ty ];
		for ( quint32 i = 0; i < uv->ary.cnt; i++ )
		{
			if ( !b_first )
				s_ret += ", ";
			b_first = false;
			Q_ASSERT( p_elem[i].basicType() == el_ty );
			s_ret += el_interf->presentation( &p_elem[i] );
		}
	}

	s_ret += "]";
	return s_ret;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				UVarAry::resetContent	( VarStore * uv )
{
	Q_ASSERT( uv->basicType() == VTY_FLAG_ARRAY );
	if ( uv->ary.cnt > 0 )
	{


	}
	uv->setGroundState();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				UVarAry::setDefault		( VarStore * uv )
{
	Q_ASSERT( uv->basicType() == VTY_FLAG_ARRAY );
	uv->ary.p_ary = NULL;
	uv->ary.cnt = 0;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				UVarAry::setValArray	(
		UserVar * trg_var, int el_cnt, StoreType ary_ty  )
{
	Q_ASSERT( ( ary_ty >= 0 ) && ( ary_ty < VTY_BASE_MAX ) );

	trg_var->resetContent();
	trg_var->data_.ty = VarStore::makeCompositeType( VTY_FLAG_ARRAY, ary_ty, 1 );
	trg_var->data_.ary.cnt = el_cnt;
	if ( el_cnt == 0 )
	{
		trg_var->data_.ary.p_ary = NULL;
		return;
	}

	VarStore * itr  = (VarStore*)malloc( sizeof( VarStore ) * el_cnt );
	trg_var->data_.ary.p_ary = itr;
	for ( int i = 0; i < el_cnt; i++ )
	{
		itr[i].ty = ary_ty;
		itr[i].l = 0;
	}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				UVarAry::setValArray	(
		UserVar * trg_var,  StoreType ary_ty, int levels, ...  )
{
	if ( levels == 0 )
		return;
	Q_ASSERT( ( ary_ty >= 0 ) && ( ary_ty < VTY_BASE_MAX ) );

	/* delete old content */
	trg_var->resetContent();


	int lvl_now = 0;
	int crt_cnt;
	va_list arguments;

	trg_var->data_.ty = ary_ty;
	trg_var->data_.ary.cnt = 0;
	trg_var->data_.ary.p_ary = NULL;

	va_start(arguments, levels);
	for (lvl_now = 0; lvl_now < levels; lvl_now++)
	{
		crt_cnt = va_arg(arguments, int );
		if ( crt_cnt == 0 )
		{
			lvl_now++;
			break;
		}

		addLevel( &trg_var->data_, crt_cnt, ary_ty );
	}
	va_end(arguments);

	/* save new type */
	trg_var->data_.ty = VarStore::makeCompositeType(
				VTY_FLAG_ARRAY, ary_ty, lvl_now );


}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				UVarAry::addLevel		(
		VarStore * uv, int el_cnt, StoreType ary_ty )
{

	if ( uv->ary.cnt == 0 )
	{
		Q_ASSERT( uv->basicType() == ary_ty );

		/* we have reached the bottom of the array */
		VarStore * itr  = (VarStore*)malloc( sizeof( VarStore ) * el_cnt );
		uv->ary.p_ary = itr;
		for ( int i = 0; i < el_cnt; i++ )
		{
			itr[i].ty = ary_ty;
			itr[i].ary.cnt = 0;
			itr[i].ary.p_ary = NULL;
		}
	}
	else
	{
		Q_ASSERT( uv->basicType() == VTY_FLAG_ARRAY );
		for ( quint32 i = 0; i < uv->ary.cnt; i++ )
		{
			addLevel( &uv->ary.p_ary[i], el_cnt, ary_ty );
		}
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString				UVarAry::typeName		( VarStore * uv )
{
	if ( uv == NULL )
		return "array";
	int i_l = uv->level();
	if ( i_l == 1 )
		return "array";
	else
		return QString( "nested array (%1)").arg( i_l );
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
bool				UVarAry::canSave		( VarStore * uv )
{
	return false;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool				UVarAry::load			( PgSave::IPgSave & stg, VarStore * uv )
{
	return false;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool				UVarAry::save			( PgSave::IPgSave & stg, VarStore * uv )
{
	return false;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool				UVarAry::blindCreate	 (
		IPgSave * intf, QString s_path, void * kb_data )
{
	BlindData * bd = (BlindData*)kb_data;
	Q_ASSERT( bd != NULL );

	/** @todo implement blindCreate for arrays */
	return true;
}
/* ========================================================================= */










#ifdef	PGSCRIPT_TESTS
#ifndef	TEST_OK
#define	TEST_OK		{Outcm = "Ok"; succeded++;}
#define	TEST_FAIL	{Outcm = "Fail"; }
#endif
/* ------------------------------------------------------------------------- */
void				PgScr::VarArray_Tests					(
		int & performed, int & succeded )
{
	QString Outcm;
	performed = 0;
	succeded = 0;

	int	test_sz = 1000;
	bool b_ok = true;
	UserVar * p_var_ary;
	p_var_ary = new UserVar( );

#define TEST_INT_SZ  5
	static int		test_int[TEST_INT_SZ] = {1, 2, 3, 4, 5};
#define TEST_INT64_SZ  5
	static qint64	test_int64[TEST_INT64_SZ] = {1, 2, 3, 4, 5};
#define TEST_DOUBLE_SZ  5
	static double	test_double[TEST_DOUBLE_SZ] = {1.1, 2.1, 3.1, 4.1, 5.1};
#define TEST_BOOL_SZ  5
	static bool		test_bool[TEST_BOOL_SZ] = {true, false, true, false, false};
#define TEST_CHAR_SZ  5
	static char		test_char[TEST_CHAR_SZ] = {'a', 'z', 't', 'y', 'b'};
#define TEST_QCHAR_SZ  5
	static QChar	test_qchar[TEST_QCHAR_SZ] = {'a', 'z', 't', 'y', 'b'};
#define TEST_COLOR_SZ  2
	static QRgb		test_color[TEST_COLOR_SZ] = {0xFFFFAABB, 0xFF00BB00};

	QStringList	testStrL;
	testStrL << "first" << "second" << "third";

	int j = 0; int i;
	qDebug() << "Now testing with a number of " << test_sz << " arrays";
	for ( i = 0; i < test_sz; i++ )
	{
		switch ( j )	{
		case	0:	{
			p_var_ary->setVal( &test_int[0], TEST_INT_SZ );
			if ( p_var_ary->presentation() != "[1, 2, 3, 4, 5]")
			{ b_ok = false; }
			break;}
		case	1:	{
			p_var_ary->setVal( &test_int64[0], TEST_INT64_SZ );
			if ( p_var_ary->presentation() != "[1, 2, 3, 4, 5]")
			{ b_ok = false; }
			break;}
		case	2:	{
			p_var_ary->setVal( &test_double[0], TEST_DOUBLE_SZ );
			if ( p_var_ary->presentation() != "[1.1, 2.1, 3.1, 4.1, 5.1]")
			{ b_ok = false; }
			break;}
		case	3:	{
			p_var_ary->setVal( &test_bool[0], TEST_BOOL_SZ );
			if ( p_var_ary->presentation() != "[true, false, true, false, false]")
			{ b_ok = false; }
			break;}
		case	4:	{
			p_var_ary->setVal( &test_char[0], TEST_CHAR_SZ );
			if ( p_var_ary->presentation() != "['a', 'z', 't', 'y', 'b']")
			{ b_ok = false; }
			break;}
		case	5:	{
			p_var_ary->setVal( &test_qchar[0], TEST_QCHAR_SZ );
			if ( p_var_ary->presentation() != "['a', 'z', 't', 'y', 'b']")
			{ b_ok = false; }
			break;}
		case	6:	{
			p_var_ary->setVal( &test_color[0], TEST_COLOR_SZ );
			if ( p_var_ary->presentation() != "[#FFFFAABB, #FF00BB00]")
			{ b_ok = false; }
			break;}
		case	7:	{
			p_var_ary->setVal( testStrL );
			if ( p_var_ary->presentation() != "[\"first\", \"second\", \"third\"]")
			{ b_ok = false; }
			break;}
		case	8:	{
			p_var_ary->setValArray( 4, VTY_BOOL );
			if ( p_var_ary->presentation() != "[false, false, false, false]")
			{ b_ok = false; }
			break;}
		case	9:	{
			p_var_ary->setValArray( 4, VTY_CHARACTER );
			if ( p_var_ary->presentation() != "[' ', ' ', ' ', ' ']")
			{ b_ok = false; }
			break;}
		case	10:	{
			p_var_ary->setValArray( 4, VTY_COLOR );
			if ( p_var_ary->presentation() != "[#FF000000, #FF000000, #FF000000, #FF000000]")
			{ b_ok = false; }
			break;}
		case	11:	{
			p_var_ary->setValArray( 4, VTY_DOUBLE );
			if ( p_var_ary->presentation() != "[0, 0, 0, 0]")
			{ b_ok = false; }
			break;}
		case	12:	{
			p_var_ary->setValArray( 4, VTY_INTEGER );
			if ( p_var_ary->presentation() != "[0, 0, 0, 0]")
			{ b_ok = false; }
			break;}
		case	13:	{
			p_var_ary->setValArray( 4, VTY_STRING );
			if ( p_var_ary->presentation() != "[\"\", \"\", \"\", \"\"]")
			{ b_ok = false; }
			break;}
		case	14:	{
			p_var_ary->setCharArray( "abcde" );
			if ( p_var_ary->presentation() != "['a', 'b', 'c', 'd', 'e']")
			{ b_ok = false; }
			break;}
		}
		if ( b_ok == false )
			break;
		j++; if ( j >= 14 ) j = 0;

	}
	if ( b_ok )	TEST_OK
			else	TEST_FAIL
			qDebug() << QString( " - setVal, resetContent, setValArray, setDefault and presentation (%1) ..." ).arg( i )
					 << Outcm;
	performed++; b_ok = true;

	bool b_conv_ok = false;


	/* this assumes that VTY_INTEGER is the first basic type */
	for ( i = VTY_INTEGER; i < VTY_DEFVAR; i++ )
	{
		p_var_ary->setValArray( 200, (StoreType)i );

		p_var_ary->convToBool( &b_conv_ok, &p_var_ary->data_ );
		if ( b_conv_ok == true )		break;
		p_var_ary->convToShort( &b_conv_ok, &p_var_ary->data_ );
		if ( b_conv_ok == true )		break;
		p_var_ary->convToInt( &b_conv_ok, &p_var_ary->data_ );
		if ( b_conv_ok == true )		break;
		p_var_ary->convToLong( &b_conv_ok, &p_var_ary->data_ );
		if ( b_conv_ok == true )		break;
		p_var_ary->convToByte( &b_conv_ok, &p_var_ary->data_ );
		if ( b_conv_ok == true )		break;
		p_var_ary->convToDouble( &b_conv_ok, &p_var_ary->data_ );
		if ( b_conv_ok == true )		break;
		p_var_ary->convToStrLst( &b_conv_ok, &p_var_ary->data_ );
		if ( b_conv_ok == true )		break;
		p_var_ary->convToStr( &b_conv_ok, &p_var_ary->data_ );
		if ( b_conv_ok == true )		break;

	}
	if ( b_conv_ok == false )	TEST_OK
			else	TEST_FAIL
			qDebug() << QString( " - convTo__ (%1) ..." ).arg( i )
					 << Outcm;
	performed++; b_ok = true;

	delete p_var_ary;

}
/* ========================================================================= */
#endif

/*  CLASS    =============================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
